using System;
using System.Xml;
using System.Xml.Serialization;
using System.Collections;

namespace G2007.CodeGen.Data
{


	[Serializable()]
	[XmlInclude(typeof(Class.ClassAttributes))]
	[XmlInclude(typeof(Data.HeaderInfo))]
	[XmlInclude(typeof(Data.Class.DeleteArray))]
	public class Class
	{


		HeaderInfo hi;

		ClassAttributes[] classAttributes;
		string name;


		[XmlIgnore()]
		Class[] otherClasses;

		[XmlIgnore()]
		Enum[] enums;



		[XmlIgnore()]
		string[] data;


		[XmlIgnore()]
		DeleteArray[] deleteArray;

		public DeleteArray[] DeleteArrayObjs
		{
			get { return deleteArray; }
			set { deleteArray=value; }
		}

		public string Name { get { return name; } set { name=value; } }
		

		public HeaderInfo @HeaderInfo { get { return hi; } set { hi=value; } }

        public bool IsCompareable
        {
            get
            {
               // foreach (ClassAttributes ca in this.classAttributes)
                //{
               //     if (ca.Compare) return true;
               // }
               // return false;
                return true;
            }
            set { int p = 0xf; }
        }


		public ClassAttributes[] ClassAttribs
		{
			get { return classAttributes; }
			set { classAttributes=value; }
		}


		public Class() {}

		public override string ToString()
		{
			string t="";
			foreach(Data.Class.ClassAttributes ca in this.classAttributes) 
			{
				t+=ca.Name + " " + ca.Type + 
					" (" + ca.CType.ToString() + ")\n";
			}
			return "Name: " + this.name + " Namespace:" + 
				this.hi.ProjectName + "\n" + t;
		}



		public Class(string name, HeaderInfo hi, string[] data, 
			Class[] otherClasses, Enum[] enums) 
		{
			this.name=name;
			this.hi=hi;
			this.enums=enums;
			
			this.data=data;
			this.otherClasses=otherClasses;
		}

		public bool GenerateFields(out string error) 
		{
			error="";
			// need to find the class in the data and then generate it

			int x=0;
            
			foreach(string s in data) 
			{
				if(s.ToUpper().StartsWith("CLASS")) 
				{
					if(s.Split('\t').Length>1) 
					{
						if(s.Split('\t')[1].Trim().Equals(name)) 
						{
							// we have found the matcing data - now we need to 
							// read until we get to end class x hold the
							// current line, so we just need to read from data
							//  from there onwards
							ArrayList vals=new ArrayList();
							int y=x+1;
							while(y<data.Length) 
							{
								if(data[y].ToUpper().Trim().Equals("END CLASS"))
									break;

								if(data[y].Split('\t').Length>1) 
								{

                                    string[] dataBlocks = data[y].Split('\t');
                                    string attributeName = dataBlocks[0].Trim();
                                    string attributeType = dataBlocks[1].Trim().Replace("[]", "");
                                    ClassType classType = dataBlocks[1].Trim().EndsWith("[]") ? ClassType.array : ClassType.single;

                                    bool toString=hasParam(dataBlocks, "TOSTRING");
                                    bool hidden = hasParam(dataBlocks, "HIDDEN");
                                    bool compare = hasParam(dataBlocks, "COMPARE");

                                    


									vals.Add(new ClassAttributes(attributeName,attributeType,classType,otherClasses,enums,toString,hidden,name,compare));
								}

								y++;
							}

							this.classAttributes=
								(ClassAttributes[])vals.ToArray(typeof(ClassAttributes));
						}
					}
				}
				x++;
			}

			return true;
		}

        private static bool hasParam(string[] dataBlocks, string val)
        {
            for (int z = 2; z < dataBlocks.Length; z++)
            {
                if (dataBlocks[z].Trim().ToUpper().Equals(val.ToUpper())) return true;
            }
            return false;
        }


		[Serializable]
		public class DeleteArray 
		{
			string name;
			string field;
			string otherClass;

			public DeleteArray() {}

			public DeleteArray(string name, string field, string otherClass) 
			{
				this.name=name;
				this.field=field;
				this.otherClass=otherClass;
			}

			public string Name { get { return name; } set { name=value; } }
			public string Field { get { return field; } set { field=value; } }
			public string OtherClass { get { return otherClass; } set { otherClass=value; } }
		}
		
	
		[Serializable]
		[XmlInclude(typeof(ClassType))]
		public class ClassAttributes 
		{
			string name, type;
			ClassType ctype;
			[XmlIgnore]
			Class[] otherClasses;
			[XmlIgnore]
			Enum[] enums;

			string className;
			bool toString=false;
            bool hidden = false;
            bool compare = false;



			public ClassAttributes() {}

			public ClassAttributes(string name, string type, ClassType ctype, Class[] otherClasses, Enum[] enums, bool toString, bool hidden, string className, bool compare) : this()
			{
				this.name=name; this.type=type; this.ctype=ctype; this.otherClasses=otherClasses; this.enums=enums; this.toString=toString;
                this.compare = compare;
                this.className = className; this.hidden = hidden;
			}

			public string Name { get { return name.Substring(0,1).ToLower() + name.Substring(1,name.Length-1); } set { name=value; } }
			public string PropertyName { get { return name.Substring(0,1).ToUpper() + name.Substring(1,name.Length-1); } set { name=value; } }
			public string Type { get { return type.Replace("big",""); } set { type=value; } }
			public bool IsEnum 
			{
				get { foreach(Data.Enum e in enums) { if(e.Name.Equals(type)) return true; } return false; }
				set { int p=0xf; p++; }
			}
			

			public bool ToString { get { return toString; } set { toString=value; } }
            public bool Hidden { get { return hidden; } set { hidden = value; } }

            public bool Compare
            {
                get { return compare; }
                set { compare = value; }
            }

			public bool KnownClass 
			{
				get {
					if(type.Equals(className)) return true;//because we might have an instance of ourselves inside ourselves (yuck)
					foreach(Class c in otherClasses) 
					{
						if(c.name.Equals(type)) return true;
					}	
					return false;
				}
				set { int p=0xf; p++; }

			}
			public ClassType CType { get { return ctype; } set { ctype=value; } }
			
			public string SqlAccess 
			{
				set { int p=0xf; p++; }
				get 
				{
					if(IsEnum) 
					{
						return "GetInt32(x)";
					}
					// we need a lookup table for this
					int x=0;
					while(true) 
					{
						string val=System.Configuration.ConfigurationSettings.AppSettings["SQLVAL[" + x + "]"];
						if(val==null || val=="") return "GetGuid(x)";

						if(val.Split('|')[0].Equals(type)) 
						{
							if(val.Split('|').Length>1) return val.Split('|')[1];
							else return "";
						}
						x++;
					}
				}
			}

			public string SqlType 
			{
				set { int p=0xf; p++; }
				get 
				{
					if(IsEnum) 
					{
						return "[int]";
					}
					int x=0;
					while(true) 
					{
						string val=System.Configuration.ConfigurationSettings.AppSettings["SQLDBVAL[" + x + "]"];
						if(val==null || val=="") return "uniqueidentifier";

						if(val.Split('|')[0].Equals(type)) 
						{
							if(val.Split('|').Length>1) return val.Split('|')[1];
							else return "";
						}
						x++;
					}
					
				}
			}

			public string SqlSPType 
			{
				set { int p=0xf; p++; }
				get 
				{
					if(IsEnum) 
					{
						return "int";
					}
					int x=0;
					while(true) 
					{
						string val=System.Configuration.ConfigurationSettings.AppSettings["SQLDBVAL[" + x + "]"];
						if(val==null || val=="") return "uniqueidentifier"; // this might need to return objectID

						if(val.Split('|')[0].Equals(type)) 
						{
							if(val.Split('|').Length>2) return val.Split('|')[2];
							else return "";
						}
						x++;
					}
					
				}
			}
		}


		public enum ClassType : int
		{
			single,array
		}
	}
}
